package com.pandora.common.aop;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import com.pandora.common.exception.EduException;
import com.pandora.common.util.StringUtils;
import com.pandora.framework.util.LogUtils;
import com.pandora.framework.util.ServiceUtils;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public abstract class AOPBaseClass implements MethodInterceptor {

	private Enhancer enhancer = new Enhancer();

	protected List<Object> interceptors = new ArrayList<Object>();

	protected List<Object> interMethodNames = new ArrayList<Object>();

	public AOPBaseClass() {
		this.initInterceptors();
		this.initInterMethodNames();
	}

	protected abstract void initInterceptors();

	protected abstract void initInterMethodNames();

	public Object bind(Class<?> cls) {

		this.enhancer.setSuperclass(cls);
		this.enhancer.setCallback(this);
		Object obj = this.enhancer.create();
		return obj;
	}

	public Object intercept(Object proxy, Method method, Object[] methodParameters, MethodProxy methodProxy)
			throws Throwable {

		Object result = null;
		InvocationInfo invInfo = null;
		Throwable ex = null;

		String methodName = method.getName();
		invInfo = new InvocationInfo(proxy, method, methodParameters, methodProxy, result, ex);

		if (this.interMethodNames.contains(methodName)) {

			try {
				invokeInterceptorsBefore(invInfo);
				result = methodProxy.invokeSuper(proxy, methodParameters);

				invInfo.setResult(result);
				invokeInterceptorsAfter(invInfo);
			} catch (Throwable e) {
				invInfo.setException(e);
				invokeInterceptorsExceptionThrow(invInfo);
				throw e;
			} finally {
				invokeInterceptorsLast(invInfo);
			}
		} else {
			result = methodProxy.invokeSuper(proxy, methodParameters);
		}

		return result;
	}

	private void invokeInterceptorsBefore(InvocationInfo invInfo) throws EduException {
		for (int i = 0; i < this.interceptors.size(); i++) {
			Interceptor interceptor = (Interceptor) this.interceptors.get(i);
			interceptor.before(invInfo);
		}
	}

	private void invokeInterceptorsAfter(InvocationInfo invInfo) throws EduException {
		for (int i = this.interceptors.size() - 1; i >= 0; i--) {
			Interceptor interceptor = (Interceptor) this.interceptors.get(i);
			interceptor.after(invInfo);
		}
	}

	private void invokeInterceptorsLast(InvocationInfo invInfo) throws EduException {
		for (int i = this.interceptors.size() - 1; i >= 0; i--) {
			Interceptor interceptor = (Interceptor) this.interceptors.get(i);
			interceptor.last(invInfo);
		}
	}

	private void invokeInterceptorsExceptionThrow(InvocationInfo invInfo) throws EduException {
		for (int i = this.interceptors.size() - 1; i >= 0; i--) {
			Interceptor interceptor = (Interceptor) this.interceptors.get(i);
			interceptor.exceptionThrow(invInfo);

			String msg = StringUtils.nullToStrTrim(invInfo.getException().getMessage());
			if (!ServiceUtils.isInfoCode(msg)) {
				LogUtils.logError(msg);
			}
		}
	}
}